/**
 * @brief rf frequency hopping, hopping when receive data successfully.
 *      Each device has its own channel map.
 * 
 * @copyright Copyright (c) 2022 zerosensei
 * 
 */
#include "rf_hop.h"
#include "sys/util.h"

const uint32_t rf_channel_map[CONFIG_RF_CHANNEL_NUM] = CONFIG_RF_CHANNEL_MAP;
static uint8_t channel_idx[2] = {0};
static bool is_hopping[2];


__attribute__((section(".highcode")))
void rf_hop_reset(struct rf_port_dev *device)
{
    if(device->dev == RF_DEV_KBD){
        is_hopping[RF_DEV_KBD] = false;
        channel_idx[RF_DEV_KBD] = 0;
        rf_set_channel(rf_channel_map[channel_idx[RF_DEV_KBD]]);
    } else if(device->dev == RF_DEV_MOUSE){
        is_hopping[RF_DEV_MOUSE] = false;
        channel_idx[RF_DEV_MOUSE] = 0;
        rf_set_channel(rf_channel_map[channel_idx[RF_DEV_MOUSE]]);
    }
}

void rf_hop_start(struct rf_port_dev *device)
{
    is_hopping[device->dev] = true;
}

/**
 * Frequency hopping is only related to the communication interval(CONFIG_RF_SYNC_UNIT_MS). 
 * Each communication event will cause both devices to hop once, if the device needs to hop.
 */
__attribute__((section(".highcode")))
void rf_hop(struct rf_port_dev *curr_dev, struct rf_port_dev device[2])
{
    static uint8_t def_idx = 0xff;

    if(!device[RF_DEV_KBD].is_lost && is_hopping[RF_DEV_KBD]){
        /* If the def_idx is valid, take over the def_idx */
        if (def_idx != 0xff) {
            channel_idx[RF_DEV_KBD] = def_idx;
            def_idx = 0xff;
        }
        channel_idx[RF_DEV_KBD]++;
        channel_idx[RF_DEV_KBD] = channel_idx[RF_DEV_KBD] % ARRAY_SIZE(rf_channel_map);
    }

    if(!device[RF_DEV_MOUSE].is_lost && is_hopping[RF_DEV_MOUSE]){
        /* If the def_idx is valid, take over the def_idx */
        if (def_idx != 0xff) {
            channel_idx[RF_DEV_MOUSE] = def_idx;
            def_idx = 0xff;
        }
        channel_idx[RF_DEV_MOUSE]++;
        channel_idx[RF_DEV_MOUSE] = channel_idx[RF_DEV_MOUSE] % ARRAY_SIZE(rf_channel_map);
    }

    if (curr_dev) {
        rf_set_channel(rf_channel_map[channel_idx[curr_dev->dev]]);
    } else {
        /** 
         * The current device is not specified, but data is received, hop as normal.
         * When the device is specified, it will take over the current channel idx 
         * and continue hopping.
         */
        if (def_idx == 0xff) {
            def_idx = 0;
        }
        def_idx++;
        def_idx = def_idx % ARRAY_SIZE(rf_channel_map);
        rf_set_channel(rf_channel_map[def_idx]);
    }

#ifdef CONFIG_RF_DEBUG_GPIO
    if(channel_idx[curr_dev->dev] == 0){
        GPIOA_InverseBits(DG_HOP_0_PIN);
    }
#endif
}
